package com.stormragetech.sylwanas.process;

import com.stormragetech.sylwanas.common.MessageWrapper;
import com.stormragetech.sylwanas.common.RabbitInfo;
import com.stormragetech.sylwanas.util.Assert;
import com.stormragetech.sylwanas.util.CommonUtils;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.ApplicationContext;

import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;

/**
 * description: //TODO
 *
 * @author Xue Bin
 * @version 1.0.0-SNAPSHOT
 */
@Log4j2
@Data
class RetryCache {

    private final RabbitInfo info;
    private final ApplicationContext context;

    private long last;

    //    private LongAdder id = new LongAdder();
    private Map<String, MessageWrapper> sMap = new ConcurrentSkipListMap<>();
    private Map<String, MessageWrapper> cMap = new ConcurrentSkipListMap<>();

    boolean stop = false;

    RetryCache(RabbitInfo info, ApplicationContext context) {
        Assert.notNull(info, "RabbitInfo cannot be null !!!");
        Assert.notNull(context, "ApplicationContext cannot be null !!!");
        this.info = info;
        this.context = context;
    }

//    public long generateId() {
//        id.increment();
//        return id.longValue();
//    }

    void add(MessageWrapper wrapper, int type) {
        if (type == 0) {
            sMap.put(wrapper.getId(), wrapper);
        } else {
            cMap.put(wrapper.getId(), wrapper);
        }
    }

    void setTime(String id) {
        sMap.get(id).setTime(System.currentTimeMillis());
    }

    void start() {
        this.stop = false;
        if (info.getSender().getSendRetryCount() > 0) {
            new Thread(() -> {
                while (!stop) {

                    CommonUtils.sleep(info.getSender().getSendRetryIntervalMils());

                    for (Map.Entry<String, MessageWrapper> entry : sMap.entrySet()) {
                        MessageWrapper wrapper = entry.getValue();
                        final long now = System.currentTimeMillis();

                        if (!wrapper.getLock().tryLock()) {
                            continue;
                        }

                        wrapper.getLock().lock();
//                    log.info("message is [ {} ] - confirm is [ {} ] - return is [ {} ] ", wrapper.getId(), wrapper.getConfirmCode(), wrapper.getReturnCode());
                        if (wrapper.getConfirmCode() < 0 || wrapper.getReturnCode() < 0) {
                            if (wrapper.increase() > info.getSender().getSendRetryCount()) {
                                sMap.remove(entry.getKey());
                                // TODO: record err into file
                            } else {
                                wrapper.getSender().send(wrapper);
                                System.out.println();
                                System.out.println("---------- ---------- ---------- ---------- ---------- ----------");
                                log.info("[ RESEND ] - [ COUNT ] - [ {} ] - [ MESSAGE - ID ] - [ {} ]", wrapper.getCount().intValue(), wrapper.getId());
                                System.out.println("---------- ---------- ---------- ---------- ---------- ----------");
                                System.out.println();
                            }
                        }
                        if (wrapper.getConfirmCode() > 0 && now - wrapper.getTime() > info.getSender().getSendTimeout()) {
                            sMap.remove(entry.getKey());
                            System.out.println();
                            System.out.println("---------- ---------- ---------- ---------- ---------- ----------");
                            log.debug("[ SUCCESS ] - [ SEND ] - [ MESSAGE - ID ] - [ {} ]", wrapper.getId());
                            System.out.println("---------- ---------- ---------- ---------- ---------- ----------");
                            System.out.println();
                        }
                        wrapper.unlock();
                    }
                }
            }).start();
        } else {
            log.info("[ SYSTEM - NORETRY - START ] start no retry thread !!!");
            new Thread(() -> {
                while (!stop) {
                    for (Map.Entry<String, MessageWrapper> entry : sMap.entrySet()) {
                        MessageWrapper wrapper = entry.getValue();
                        final long now = System.currentTimeMillis();
                        if (!wrapper.getLock().tryLock()) {
                            continue;
                        }

                        wrapper.getLock().lock();
                        if (wrapper.getConfirmCode() < 0 || wrapper.getReturnCode() < 0) {
                            // TODO: record err into file
                            log.info("save err to file");
                        } else if (wrapper.getConfirmCode() > 0 && now - wrapper.getTime() > info.getSender().getSendTimeout()) {
                            sMap.remove(entry.getKey());
                        }
                        wrapper.unlock();
                    }
                }
            }).start();
        }
        Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
    }

    void stop() {
        this.stop = true;
        log.info("[ SYSTEM - CACHE - STOP ] stop cache thread !!!");
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
